package org.zcl.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.zcl.dao.ActivityDao;
import org.zcl.dao.AwardDao;
import org.zcl.dao.AwardRecordDao;
import org.zcl.entity.po.Activity;
import org.zcl.entity.po.Award;
import org.zcl.entity.po.AwardRecord;
import org.zcl.entity.response.LotteryVO;
import org.zcl.enums.CacheKeyEnum;
import org.zcl.entity.model.CacheKey;
import org.zcl.service.AwardService;
import org.zcl.utils.CacheUtil;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;

/**
 * 奖品(Award)表服务实现类
 *
 * @author Chenglin Zhu
 * @since 2022-01-28 11:18:56
 */
@Service("awardService")
@Slf4j
public class AwardServiceImpl extends ServiceImpl<AwardDao, Award> implements AwardService {

    @Autowired
    private AwardDao awardDao;

    @Autowired
    private ActivityDao activityDao;

    @Autowired
    private AwardRecordDao awardRecordDao;

    @Autowired
    private CacheUtil cacheUtil;

    @Override
    public Boolean initLotteryPool(Integer activityId) {
        Activity activity = activityDao.selectById(activityId);
        if (activity == null) {
            throw new RuntimeException("该活动不存在！");
        }
        CompletableFuture<Boolean> cf =  CompletableFuture.supplyAsync(() -> checkAndExecuteInit(activity));
        try {
            return cf.get();
        } catch (InterruptedException | ExecutionException e) {
            return false;
        }
    }

    @Override
    public LotteryVO doLottery(Integer activityId) {
        // 抽奖次数限制......
        // 抽奖概率
        int randomInt = RandomUtils.nextInt(1, 101);
        if (randomInt < 10) {
            return LotteryVO.builder().amount(null).result("未中奖！").build();
        }
        // 抽奖
        String value = cacheUtil.lPop(CacheKey.getKey(CacheKeyEnum.LOTTERY_PREFIX) + activityId);
        Award award = awardDao.selectById(value);
        // 记录
        if (award != null) {
            awardRecordDao.insert(AwardRecord.builder().awardId(award.getId()).activityId(activityId).build());
            return LotteryVO.builder().amount(award.getAmount()).result("恭喜中奖！").build();
        }
        return LotteryVO.builder().amount(null).result("已结束！").build();
    }

    private Boolean checkAndExecuteInit(Activity activity) {
        List<Award> awards = awardDao.selectList(new LambdaQueryWrapper<Award>().eq(Award::getActivityId, activity.getId()));
        List<Integer> awardIds = new ArrayList<>();
        for (Award award : awards) {
            Integer awardCount = award.getAwardCount();
            // 查询记录
            List<AwardRecord> awardRecords = awardRecordDao.selectList(new LambdaQueryWrapper<AwardRecord>()
                    .eq(AwardRecord::getActivityId, activity.getId())
                    .eq(AwardRecord::getAwardId, award.getId())
            );
            if (awardRecords.size() > 0 && (awardCount = awardCount - awardRecords.size()) < 0) {
                log.info("该奖品的奖品数量小于已抽中该奖品的数量，无法进行初始化!");
                continue;
            }
            awardIds.addAll(getNoSortedAwardsIds(award.getId(), awardCount));
        }
        if (!CollectionUtils.isEmpty(awardIds)) {
            // 打乱顺序
            Collections.shuffle(awardIds);
            String key = CacheKey.getKey(CacheKeyEnum.LOTTERY_PREFIX) + activity.getId();
            // redis操作，先清空，然后再插入
            cacheUtil.deleteKey(key);
            cacheUtil.rightPushAll(key, awardIds.stream().map(String::valueOf).collect(Collectors.toList()));
            return true;
        }
        return false;
    }

    private List<Integer> getNoSortedAwardsIds(Integer activityAwardsId, int awardsNum) {
        if (awardsNum <= 0) {
            return Collections.emptyList();
        }
        List<Integer> noSortedAwardsIds = Lists.newArrayListWithCapacity(awardsNum);
        for (int i = 0; i < awardsNum; i++) {
            noSortedAwardsIds.add(activityAwardsId);
        }
        return noSortedAwardsIds;
    }
}

